/**
 * @file		TemperatureSensor.c
 * @brief		Temperature Sensor
 * @note		None
 * @attention	None
 * 
 * <B><I>ALL RIGHTS RESERVED, COPYRIGHT&copy; SOCIONEXT INCORPORATED 2016</I></B>
 */

/* Standard includes. */
#include <stdio.h>
#include <string.h>

#include "dd_arm.h"

/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"

#include "dd_pmc_temp_sensor_if.h"
#include "TemperatureSensor.h"

#include "ipcu.h"

// Notification enable.
static volatile int iNotificationEnable = 0;

// Buffer data.
static volatile T_TEMP_SENSOR_BUFFER xBuffer = { 0, 0, 0, 0 };

// Interrupt type.
static unsigned long ulInterruptType = 0;


// Local function.
static void prvTemperatureSensorCallback(int interrupt);


/**
Temperature Sensor callback function.
*/
static void prvTemperatureSensorCallback(int interrupt)
{
	BaseType_t		xHigherPriorityTaskWoken, xResult;
	unsigned long	ulData[4];
	
	// check interrupt factor.
	if ((interrupt & D_DD_PMC_TS_IF_INT_TYPE_ALL) == D_DD_PMC_TS_IF_INT_TYPE_ALL) {
		// All Sensers.
		switch (interrupt & 0x0000000F) {
			case D_DD_PMC_TS_IF_INT_STATUS_LF:	// exceed low temperature.
				ulInterruptType = D_TEMP_SENSOR_INT_LF;
				break;
			case D_DD_PMC_TS_IF_INT_STATUS_LN:	// approach low temperature.
				ulInterruptType = D_TEMP_SENSOR_INT_LN;
				break;
			case D_DD_PMC_TS_IF_INT_STATUS_HN:	// approach high temperature.
				ulInterruptType = D_TEMP_SENSOR_INT_HN;
				break;
			case D_DD_PMC_TS_IF_INT_STATUS_HF:	// exceed high temperature.
				ulInterruptType = D_TEMP_SENSOR_INT_HF;
				break;
			default:
				break;
		}
	}
	if ((interrupt & D_DD_PMC_TS_IF_INT_TYPE_TS0) == D_DD_PMC_TS_IF_INT_TYPE_TS0) {
		// Senser#0.
		switch (interrupt & 0x0000000F) {
			case D_DD_PMC_TS_IF_INT_STATUS_LF:	// exceed low temperature.
				ulInterruptType = D_TEMP_SENSOR_INT_LF;
				break;
			case D_DD_PMC_TS_IF_INT_STATUS_LN:	// approach low temperature.
				ulInterruptType = D_TEMP_SENSOR_INT_LN;
				break;
			case D_DD_PMC_TS_IF_INT_STATUS_HN:	// approach high temperature.
				ulInterruptType = D_TEMP_SENSOR_INT_HN;
				break;
			case D_DD_PMC_TS_IF_INT_STATUS_HF:	// exceed high temperature.
				ulInterruptType = D_TEMP_SENSOR_INT_HF;
				break;
			default:
				break;
		}
	}
	
	// Notification.
	if (iNotificationEnable) {
		xHigherPriorityTaskWoken = pdFALSE;
		
		// Set Temperature Sensor Notify data
		ulData[0] = 0x0200000A;
		ulData[1] = 0;
		ulData[2] = 0;
		ulData[3] = ulInterruptType;
		vIPCUSetNotifyCommand(ulData, 4);
		
		// Set Event Flag : Temperature Sensor Notification.
		xResult = xEventGroupSetBitsFromISR(xNotifyEventFlag, (1 << NFY_TEMPERATURE), &xHigherPriorityTaskWoken);
		if (xResult == pdPASS) {
			portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
		}
	}
}

/**
Temperature Sensor start.
@retval  0 : success
@retval  3 : function error
*/
#ifdef SET_TEMPERATURE_SENSOR_ALL
int iTemperatureAllSensorStart(void)
{
	T_DD_PMC_TS_IF_ALL xCtrl_all = {0};
	
	Dd_PMC_TS_IF_Set_All_Config(E_DD_PMC_TS_IF_CONFIG_ALL_SETTING);
	
	xCtrl_all.ts_reset				= D_DD_PMC_TS_IF_ENABLE_ON;
	xCtrl_all.ts_en					= D_DD_PMC_TS_IF_ENABLE_ON;

	xCtrl_all.ts_ct					= E_DD_PMC_TS_IF_CT_0;
	xCtrl_all.irq_mask.bit.ts_irq_0		= D_DD_PMC_TS_IF_ENABLE_OFF;
	//xCtrl_all.irq_mask.bit.ts_irq_0		= D_DD_PMC_TS_IF_ENABLE_ON;
	xCtrl_all.irq_mask.bit.all_lf_irq	= D_DD_PMC_TS_IF_ENABLE_ON;
	xCtrl_all.irq_mask.bit.all_ln_irq	= D_DD_PMC_TS_IF_ENABLE_ON;
	xCtrl_all.irq_mask.bit.all_hn_irq	= D_DD_PMC_TS_IF_ENABLE_ON;
	xCtrl_all.irq_mask.bit.all_hf_irq	= D_DD_PMC_TS_IF_ENABLE_ON;
	xCtrl_all.irq_mask.bit.any_lf_irq	= D_DD_PMC_TS_IF_ENABLE_OFF;
	xCtrl_all.irq_mask.bit.any_ln_irq	= D_DD_PMC_TS_IF_ENABLE_OFF;
	xCtrl_all.irq_mask.bit.any_hn_irq	= D_DD_PMC_TS_IF_ENABLE_OFF;
	xCtrl_all.irq_mask.bit.any_hf_irq	= D_DD_PMC_TS_IF_ENABLE_OFF;
	xCtrl_all.hi_full_temp			= xBuffer.hi_full_temp;
	xCtrl_all.hi_near_temp			= xBuffer.hi_near_temp;
	xCtrl_all.lo_near_temp			= xBuffer.lo_near_temp;
	xCtrl_all.lo_full_temp			= xBuffer.lo_full_temp;
	xCtrl_all.hys_temp				= 0x00;
	xCtrl_all.callback				= (VP_CALLBACK)prvTemperatureSensorCallback;
	
	// Set Control Information.
	if(D_DDIM_OK != Dd_PMC_TS_IF_Set_Control_All_Sensors(&xCtrl_all)) {
		// function error.
		return 3;
	}
#if 0
	printf("--- Temp Sensor All-IF Register ---\n");
	printf("SENSOR - HI_FULL_TEMP : 0x%08lx\n", xCtrl_all.hi_full_temp);
	printf("SENSOR - HI_NEAR_TEMP : 0x%08lx\n", xCtrl_all.hi_near_temp);
	printf("SENSOR - LO_NEAR_TEMP : 0x%08lx\n", xCtrl_all.lo_near_temp);
	printf("SENSOR - LO_FULL_TEMP : 0x%08lx\n", xCtrl_all.lo_full_temp);
	printf("SENSOR - HYS_TEMP     : 0x%08x\n", xCtrl_all.hys_temp);
	printf("SENSOR - IRQMASK      : 0x%08lx\n", xCtrl.irq_mask.word);
	printf("SENSOR - TS_CT        : 0x%08x\n", (unsigned char)xCtrl_all.ts_ct);
	printf("SENSOR - TS_EN        : 0x%08x\n", xCtrl_all.ts_en);
	printf("SENSOR - TS_RESET     : 0x%08x\n", xCtrl_all.ts_reset);
#endif
	// normal end.
	return 0;
}
#endif
int iTemperatureSensorStart(void)
{
	T_DD_PMC_TS_IF_EACH	xCtrl = {0};
	
	Dd_PMC_TS_IF_Set_All_Config(E_DD_PMC_TS_IF_CONFIG_EACH_SETTING);
	
	xCtrl.ts_reset				= D_DD_PMC_TS_IF_ENABLE_ON;
	xCtrl.ts_en					= D_DD_PMC_TS_IF_ENABLE_ON;

	xCtrl.ts_ct					= E_DD_PMC_TS_IF_CT_0;
	xCtrl.irq_mask.bit.lf_irq	= D_DD_PMC_TS_IF_ENABLE_ON;
	xCtrl.irq_mask.bit.ln_irq	= D_DD_PMC_TS_IF_ENABLE_ON;
	xCtrl.irq_mask.bit.hn_irq	= D_DD_PMC_TS_IF_ENABLE_ON;
	xCtrl.irq_mask.bit.hf_irq	= D_DD_PMC_TS_IF_ENABLE_ON;
	xCtrl.hi_full_temp			= xBuffer.hi_full_temp;
	xCtrl.hi_near_temp			= xBuffer.hi_near_temp;
	xCtrl.lo_near_temp			= xBuffer.lo_near_temp;
	xCtrl.lo_full_temp			= xBuffer.lo_full_temp;
	xCtrl.hys_temp				= 0x00;
	xCtrl.callback				= (VP_CALLBACK)prvTemperatureSensorCallback;
	
	// Set Control Information.
	if (D_DDIM_OK != Dd_PMC_TS_IF_Set_Control_Each_Sensor(&xCtrl)) {
		// function error.
		return 3;
	}

#if 0
	memset(&xCtrl, 0x00, sizeof(T_DD_PMC_TS_IF_EACH));
	Dd_PMC_TS_IF_Get_Control_Each_Sensor(&xCtrl);
	printf("--- Temp Sensor # IF Register ---\n");
	printf("SENSOR - HI_FULL_TEMP : 0x%08lx\n", xCtrl.hi_full_temp);
	printf("SENSOR - HI_NEAR_TEMP : 0x%08lx\n", xCtrl.hi_near_temp);
	printf("SENSOR - LO_NEAR_TEMP : 0x%08lx\n", xCtrl.lo_near_temp);
	printf("SENSOR - LO_FULL_TEMP : 0x%08lx\n", xCtrl.lo_full_temp);
	printf("SENSOR - HYS_TEMP     : 0x%08x\n", xCtrl.hys_temp);
	printf("SENSOR - IRQMASK      : 0x%08lx\n", xCtrl.irq_mask.word);
	printf("SENSOR - TS_CT        : 0x%08x\n", (unsigned char)xCtrl.ts_ct);
	printf("SENSOR - TS_EN        : 0x%08x\n", xCtrl.ts_en);
	printf("SENSOR - TS_RESET     : 0x%08x\n", xCtrl.ts_reset);
#endif
	// normal end.
	return 0;
}

/**
Temperature Sensor stop.
@retval  0 : success
@retval  3 : function error
*/
#ifdef SET_TEMPERATURE_SENSOR_ALL
int iTemperatureAllSensorStop(void)
{
	T_DD_PMC_TS_IF_ALL	xCtrl_all;
	
	// Get Control Information.
	if (D_DDIM_OK != Dd_PMC_TS_IF_Get_Control_All_Sensors(&xCtrl_all)) {
		// function error.
		return 3;
	}
	
	// Sensor#0 disable.
	xCtrl_all.ts_en = D_DD_PMC_TS_IF_ENABLE_OFF;
	
	// Set Control Information.
	if (D_DDIM_OK != Dd_PMC_TS_IF_Set_Control_All_Sensors(&xCtrl_all)) {
		// function error.
		return 3;
	}
	
	// success.
	return 0;
}
#endif
int iTemperatureSensorStop(void)
{
	T_DD_PMC_TS_IF_EACH	xCtrl;
	
	// Get Control Information.
	if (D_DDIM_OK != Dd_PMC_TS_IF_Get_Control_Each_Sensor(&xCtrl)) {
		// function error.
		return 3;
	}
	
	// Sensor#0 disable.
	xCtrl.ts_en = D_DD_PMC_TS_IF_ENABLE_OFF;
	
	// Set Control Information.
	if (D_DDIM_OK != Dd_PMC_TS_IF_Set_Control_Each_Sensor(&xCtrl)) {
		// function error.
		return 3;
	}
	
	// success.
	return 0;
}

/**
Temperature Sensor notification.
@param [in]	enable		notification enable.<br>
						0:no-notify, 1:notify by IPCU
@retval  0 : success
@retval  1 : parameter error
*/
int iTemperatureSensorNotification(int enable)
{
	if ((enable != 0) && (enable != 1)) {
		// parameter error.
		return 1;
	}
	
	// Set notification.
	iNotificationEnable = enable;
	
	// normal end.
	return 0;
}

/**
Set Temperature Sensor Buffer.
@param [in]	buff		Buffer data.
@retval  0 : success
@retval  1 : parameter error
*/
int iTemperatureSensorSetBuffer(T_TEMP_SENSOR_BUFFER const *const buff)
{
	if (!buff) {
		printf("iTemperatureSensorSetBuffer, parameter error\n");
		return -1;
	}

	///Warning! the "hi_full_temp" only can set at "0x0000027F"(79.875 degree), otherwise Timer interrupt will not occur!
	xBuffer = *buff;
	if(0x0000027F < xBuffer.hi_full_temp) {
		xBuffer.hi_full_temp = 0x0000027F;
	}
	if(0x00000270 < xBuffer.hi_near_temp) {
		xBuffer.hi_near_temp = 0x00000270;
	}
	if(xBuffer.hi_full_temp <= xBuffer.hi_near_temp) {
		xBuffer.hi_full_temp = xBuffer.hi_near_temp; //"hi_full_temp" must smart than "hi_near_temp"
		xBuffer.hi_near_temp = xBuffer.hi_full_temp - 10;
	}
	// normal end.
	return 0;
}
int iTemperatureSensorGetBuffer(T_TEMP_SENSOR_BUFFER *buff)
{
	if (!buff) {
		printf("iTemperatureSensorGetBuffer, parameter error\n");
		return -1;
	}
	
	*buff = xBuffer;
	
	// normal end.
	return 0;
}

/**
Get Measured Temperature Data.
@param [out]	cmd		Command data (GET Temperature data).<br>
@retval  0 : success
@retval  3 : function error
*/
int iTemperatureSensorGetTemperatureData(unsigned *cmd)
{
	T_DD_PMC_TS_IF_TS_DATA ts_data;
	
	// Get
	Dd_PMC_TS_IF_Get_TS_Data(&ts_data);
	
	// data check.
	if (ts_data.ts_data_valid == 0) {
		// function error.
		return 3;
	}
	
	// Set measured temperature data.
	cmd[2] = ts_data.ts_data;
	
	// normal end.
	return 0;
}

/**
Get Temperature Sensor Interrupt type.
@retval		Interrupt type : D_TEMP_SENSOR_INT_LF - D_TEMP_SENSOR_INT_HF
*/
unsigned long ulTemperatureSensorGetInterruptType(void)
{
	return ulInterruptType;
}

